# -*- coding:utf-8 -*-
"""
@author: ksf

@since: 2020/9/18 5:46 PM
"""

import os
import shutil
import yaml
from dataclasses import dataclass
from .utils import ensure_directory, merge_dict
from .logger import sys_logger
from vcat import VCAT_PATH
from vcat.core.constant import RunningMod
ROOT_PATH = os.path.dirname(os.path.dirname(__file__))


@dataclass
class ConfigFilePath:
    path: str
    filename: str
    app_name: str
    mod: RunningMod

    def __post_init__(self):
        self.fullname = os.path.join(self.path, self.filename).format(app_name=self.app_name,
                                                                      mod=self.mod.name.lower())


class BaseConfigManager:
    ROOT_PATH = ROOT_PATH
    CUSTOM_DIR = os.environ.get(VCAT_PATH, None)
    if CUSTOM_DIR is None:
        CUSTOM_DIR = os.path.expanduser(r'~\.vcat')
    ensure_directory(CUSTOM_DIR)

    def __init__(self, mod=RunningMod.REAL, app_name=None):
        self._mod = mod
        self._app_name = app_name or 'engine'

        self.SEARCH_PATHS = (
            ConfigFilePath(path=ROOT_PATH, filename='config.{app_name}.{mod}.yml',
                           app_name=self._app_name, mod=mod),
            ConfigFilePath(path=self.CUSTOM_DIR, filename='config.{app_name}.{mod}.yml',
                           app_name=self._app_name, mod=mod)

        )
        self._config_obj = self.merge_all()

    def get_root_dir(self, name):
        """
        获取 root 目录
        :return:
        """
        return self.SEARCH_PATHS[0].path

    def get_root_config_path(self):
        """
        获取root目录下自带配置文件路径
        :return:
        """
        root_config = self.SEARCH_PATHS[0]
        return root_config.fullname

    @classmethod
    def get_user_dir(cls):
        """
        用户配置目录. 用于放置数据和配置
        """
        return cls.CUSTOM_DIR

    def get_user_config_path(self):
        """
        获取用户家目录下用户自定义配置文件路径
        :return:
        """
        root_config = self.SEARCH_PATHS[-1]
        return root_config.fullname

    def get_config(self):
        return self._config_obj

    def merge_all(self):
        """
        遍历配置文件、合并所有config，后面的配置会覆盖前面的同名配置
        :return:
        """
        self._config_obj = {}
        for config_path in self.SEARCH_PATHS:
            print(config_path)
            file_path = config_path.fullname
            try:
                config_obj = self.read_yml(file_path)
                out = merge_dict(self._config_obj, config_obj)
            except FileNotFoundError:
                self.save()

        return self._config_obj

    @staticmethod
    def read_yml(file_path):
        with open(file_path, 'r', encoding='utf-8') as f:
            config_obj = yaml.safe_load(f)
            return config_obj

    def generate_config_file(self, directory=None):
        """
        生成配置文件
        :param directory: 配置文件保存的目录. 若为 None 则保存在默认位置
        :return: 生成的配置文件路径
        """
        if not directory:
            directory = self.get_user_dir()
        ensure_directory(directory)
        shutil.copy(self.get_root_config_path(), self.get_user_config_path())
        sys_logger.info(f"generate config file: {self.get_user_config_path()}")
        return self.get_user_config_path()

    def get_version(self):
        """
        获取 当前插件 版本
        :return:
        """
        try:
            with open(os.path.join(self.get_root_dir(self._app_name), 'VERSION.txt'), 'r', encoding='utf-8') as f:
                return f.read()
        except (FileExistsError, FileNotFoundError):
            return '0.0.0'

    def from_dict(self, d):
        """
        从字典生成配置
        :param d:
        :return:
        """
        self._config_obj = merge_dict(self._config_obj, d)
        return self

    def save(self):
        """
        保存到用户家目录的配置文件
        项目目录配置文件不支持自动保存，只能手动修改
        :return:
        """
        path = self.get_user_config_path()
        with open(path, mode='w+') as f:
            yaml.safe_dump(self._config_obj, stream=f)


class AppConfigManager(BaseConfigManager):

    def __init__(self, mod=RunningMod.REAL, app_name=None):
        super(AppConfigManager, self).__init__(mod=mod, app_name=app_name)
        self.SEARCH_PATHS = (ConfigFilePath(path=os.path.join(ROOT_PATH, 'apps', '{app_name}'),
                                            filename='config.{mod}.yml', mod=mod, app_name=app_name),
                             ConfigFilePath(path=os.path.join(self.CUSTOM_DIR, 'apps_config'),
                                            filename='{app_name}.{mod}.yml',
                                            mod=mod, app_name=app_name))
